package com.hnjfzn.mall.utils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class SnowflakeIdGenerator {

    // 默认的时间起始戳
    private static final long TWEPOCH = 1288834974657L;
    private static final long WORKER_ID_BITS = 5L;        // 机器 ID 的位数
    private static final long DATA_CENTER_ID_BITS = 5L;   // 数据中心 ID 的位数
    private static final long SEQUENCE_BITS = 12L;        // 序列号的位数

    // 机器 ID 最大值（31 台机器）
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    // 数据中心 ID 最大值（31 个数据中心）
    private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
    // 序列号最大值（每毫秒最多生成 4095 个 ID）
    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

    private long workerId;           // 工作机器 ID
    private long dataCenterId;       // 数据中心 ID
    private long sequence = 0L;      // 序列号
    private long lastTimestamp = -1L; // 上次生成 ID 的时间戳

    // 构造函数，传入机器 ID 和数据中心 ID
    public SnowflakeIdGenerator(long workerId, long dataCenterId) {
        if (workerId < 0 || workerId > MAX_WORKER_ID) {
            throw new IllegalArgumentException("Worker ID out of range");
        }
        if (dataCenterId < 0 || dataCenterId > MAX_DATA_CENTER_ID) {
            throw new IllegalArgumentException("Data Center ID out of range");
        }
        this.workerId = workerId;
        this.dataCenterId = dataCenterId;
    }

    // 获取当前时间戳
    private long currentTimestamp() {
        return System.currentTimeMillis();
    }

    // 生成唯一的 ID
    public synchronized long generateId() {
        long timestamp = currentTimestamp();

        // 如果当前时间戳和上次生成 ID 的时间戳相同，生成序列号
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK; // 序列号递增并与掩码相与，防止溢出
            if (sequence == 0) {
                // 如果序列号达到最大值，等待下一个毫秒
                timestamp = waitNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L; // 如果时间戳不同，重置序列号
        }

        // 如果当前时间戳小于上次生成 ID 的时间戳，则说明系统时钟回退，抛出异常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards, refusing to generate id");
        }

        lastTimestamp = timestamp;

        // 将各部分拼接成最终的 ID
        return ((timestamp - TWEPOCH) << (WORKER_ID_BITS + DATA_CENTER_ID_BITS + SEQUENCE_BITS)) // 时间戳部分
                | (dataCenterId << (WORKER_ID_BITS + SEQUENCE_BITS)) // 数据中心部分
                | (workerId << SEQUENCE_BITS)  // 机器 ID 部分
                | sequence;  // 序列号部分
    }

    // 等待下一个毫秒
    private long waitNextMillis(long lastTimestamp) {
        long timestamp = currentTimestamp();
        while (timestamp <= lastTimestamp) {
            timestamp = currentTimestamp();
        }
        return timestamp;
    }
}


